package pl.kosmowska.ewelina.client.app.activity;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import pl.kosmowska.ewelina.client.app.ClientFactory;
import pl.kosmowska.ewelina.client.app.activity.places.ChartPlace;
import pl.kosmowska.ewelina.client.app.activity.places.SignInPlace;
import pl.kosmowska.ewelina.client.app.requestfactory.dto.OutcomeDataProxy;
import pl.kosmowska.ewelina.client.app.user.AuthEvent;
import pl.kosmowska.ewelina.client.app.user.AuthEvent.Auth;
import pl.kosmowska.ewelina.client.app.user.AuthEventHandler;
import pl.kosmowska.ewelina.client.views.ChartView;
import pl.kosmowska.ewelina.client.views.impl.CategoryForChart;

import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.visualization.client.AbstractDataTable;
import com.google.gwt.visualization.client.AbstractDataTable.ColumnType;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.visualizations.corechart.CoreChart;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.ServerFailure;

public class ChartActivity extends AbstractActivity implements ChartView.Presenter{

	private ChartView view;
	private ClientFactory clientFactory;


	public ChartActivity(ChartPlace place, ClientFactory clientFactory) {
		this.clientFactory = clientFactory;
	}

	@Override
	public void start(AcceptsOneWidget containerWidget, EventBus eventBus) {
		view = clientFactory.getChartView();
		view.setPresenter(this);
		initAuthorisationForView();
		startView();
		containerWidget.setWidget(view.asWidget());
	}

	private void initAuthorisationForView() {
		if (view.isAlreadyInit() == false) {
			clientFactory.getEventBus().addHandler(AuthEvent.TYPE, new AuthEventHandler() {
				public void onAuthEvent(AuthEvent event) {
					Auth e = event.getAuthEvent();
					if (e == Auth.LOGGEDIN) {
						loadDataForCharts();
					} else if (e == Auth.LOGGEDOUT) {
						goTo(new SignInPlace());
					}
				}
			});
		}
		view.setAlreadyInit(true);
	}
	
	private void startView() {
		if (clientFactory.getIsLoggedIn() == null) {
			// wait for login event b/c hasn't happened yet
		} else if (clientFactory.getIsLoggedIn() == true) {
			loadDataForCharts();
		} else if (clientFactory.getIsLoggedIn() == false) { 
			goTo(new SignInPlace());
		}
	}
	
	public void goTo(Place place) {
		clientFactory.getPlaceController().goTo(place);
	}
	@Override
	public void loadDataForCharts() {
		clientFactory.getAppLoadingView().startProcessing();
		Request<List<OutcomeDataProxy>> req = clientFactory.getRequestFactory().getOutcomeDataRequest().findOutcomeDataByUser(new Date());
		req.fire(new Receiver<List<OutcomeDataProxy>>() {
			public void onSuccess(List<OutcomeDataProxy> outcomeDataList) {
				loadCharts(outcomeDataList);
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
				clientFactory.getAppLoadingView().stopProcessing();
			}
		});
	}

	private void loadCharts(
			final List<OutcomeDataProxy> outcomeDataList) {
		Runnable onLoadCallback = new Runnable() {
			public void run() {
				List<OutcomeDataProxy> outcomeList = new ArrayList<OutcomeDataProxy>();
				List<OutcomeDataProxy> incomeList = new ArrayList<OutcomeDataProxy>();
				float incomeValue = 0;
				float outcomeValue = 0;
				float incomeRepeatedValue = 0;
				float outcomeRepeatedValue = 0;
				float incomeNonRepeatedValue = 0;
				float outcomeNonRepeatedValue = 0;
				for(OutcomeDataProxy outcomeDataProxy :outcomeDataList){
					if(outcomeDataProxy.getValue()>0){
						incomeValue+=outcomeDataProxy.getValue();
						incomeList.add(outcomeDataProxy);
						if(outcomeDataProxy.isMultiple())
							incomeRepeatedValue+=outcomeDataProxy.getValue();
						else
							incomeNonRepeatedValue+=outcomeDataProxy.getValue(); 
					}else{
						outcomeValue+=outcomeDataProxy.getValue();
						outcomeList.add(outcomeDataProxy);
						if(outcomeDataProxy.isMultiple())
							outcomeRepeatedValue+=outcomeDataProxy.getValue();
						else
							outcomeNonRepeatedValue+=outcomeDataProxy.getValue(); 
					}

				}

				view.initOutcomeVsIncomeChart(buildIncomeVsOutcomeTable(incomeValue, outcomeValue));
				view.initOutcomeCategoryChart(buildCategoryChartTable(outcomeList));
				view.initIncomeCategoryChart(buildCategoryChartTable(incomeList));
				view.initBalanceChart(buildBalanceChartTable(outcomeDataList));
				view.initOutcomeRepeatedChart(buildOutcomeRepeatedTable(outcomeRepeatedValue, outcomeNonRepeatedValue));
				view.initIncomeRepeatedChart(buildIncomeRepeatedTable(incomeRepeatedValue, incomeNonRepeatedValue));
				boolean balancePositive = incomeValue+outcomeValue>0 ? true: false;
				view.initFinalBalanceChart(buildFinalBalanceTable(incomeValue+outcomeValue),balancePositive);
				clientFactory.getAppLoadingView().stopProcessing();
			}
		};
		VisualizationUtils.loadVisualizationApi(onLoadCallback,CoreChart.PACKAGE);


	}

	private AbstractDataTable buildIncomeVsOutcomeTable(
			float incomeValue, float outcomeValue) {
		DataTable data = DataTable.create();
		data.addColumn(ColumnType.STRING, "Aktualny okres");
		data.addColumn(ColumnType.NUMBER, "Przychody");
		data.addColumn(ColumnType.NUMBER, "Wydatki");
		data.addRows(1);
		data.setValue(0, 0, "Aktualny miesiąc");
		data.setValue(0, 1, incomeValue);
		data.setValue(0, 2, abs(outcomeValue));
		return data;
	}

	private AbstractDataTable buildCategoryChartTable(List<OutcomeDataProxy> outcomeDataList) {
		List<CategoryForChart> categoryList = divideIntoCategories(outcomeDataList);
		DataTable data = DataTable.create();
		data.addColumn(ColumnType.STRING, "Nazwa kategorii");
		data.addColumn(ColumnType.NUMBER, "Wartość");
		data.addRows(categoryList.size());
		for(int i=0; i<categoryList.size();i++){
			CategoryForChart currentCategory =categoryList.get(i);
			data.setValue(i, 0, currentCategory.getName());
			data.setValue(i, 1, abs(currentCategory.getValue()));
		}
		return data;

	}

	private List<CategoryForChart> divideIntoCategories(List<OutcomeDataProxy> outcomeDataList) {
		List<CategoryForChart> categoryList= new ArrayList<CategoryForChart>();
		for(OutcomeDataProxy outcomeDataProxy : outcomeDataList ){
			CategoryForChart foundCategory=findMyCategory(categoryList, outcomeDataProxy.getCategory());
			foundCategory.addValue(outcomeDataProxy.getValue());
		}
		return categoryList;

	}

	private CategoryForChart findMyCategory(List<CategoryForChart> categoryList, String category) {
		for(CategoryForChart categoryForChart: categoryList){
			if ((categoryForChart.getName()).equals(category))
				return categoryForChart;
		}
		CategoryForChart newCategory = new CategoryForChart();
		categoryList.add(newCategory);
		newCategory.setName(category);
		return newCategory;
	}

	private float abs(float value) {
		if (value>0)
			return value;
		else
			return (-value);
	}
	
	protected AbstractDataTable buildBalanceChartTable(
			List<OutcomeDataProxy> outcomeDataList) {
		DataTable data = DataTable.create();
		data.addColumn(ColumnType.STRING, "Data");
		data.addColumn(ColumnType.NUMBER, "Bilans");
		data.addRows(outcomeDataList.size()+1);
		float currentValue = 0;
		data.setValue(0, 0, "");
		data.setValue(0, 1, currentValue);
		for(int i=0; i<outcomeDataList.size();i++){
			OutcomeDataProxy outcomeDataProxy =outcomeDataList.get(i);
			currentValue+=outcomeDataProxy.getValue();
			data.setValue(i+1, 0, String.valueOf(outcomeDataProxy.getDate().getDate())+"/"+ String.valueOf(outcomeDataProxy.getDate().getMonth()+1)  );
			data.setValue(i+1, 1, currentValue);
		}
		return data;
	}
	
	protected AbstractDataTable buildIncomeRepeatedTable(float repeatedValue,
			float nonRepeatedValue) {
		DataTable data = DataTable.create();
		data.addColumn(ColumnType.STRING, "");
		data.addColumn(ColumnType.NUMBER, "Przychody sta\u0142e");
		data.addColumn(ColumnType.NUMBER, "Przychody pojedy\u0144cze");
		data.addRows(1);
		data.setValue(0, 0, "");
		data.setValue(0, 1, abs (repeatedValue));
		data.setValue(0, 2, abs (nonRepeatedValue));
		return data;
	}
	
	protected AbstractDataTable buildOutcomeRepeatedTable(float repeatedValue,
			float nonRepeatedValue) {
		DataTable data = DataTable.create();
		data.addColumn(ColumnType.STRING, "");
		data.addColumn(ColumnType.NUMBER, "Wydatki sta\u0142e");
		data.addColumn(ColumnType.NUMBER, "Wydatki pojedy\u0144cze");
		data.addRows(1);
		data.setValue(0, 0, "");
		data.setValue(0, 1, abs (repeatedValue));
		data.setValue(0, 2, abs( nonRepeatedValue));
		return data;
	}
	
	protected AbstractDataTable buildFinalBalanceTable(float value) {
		DataTable data = DataTable.create();
		data.addColumn(ColumnType.STRING, "");
		data.addColumn(ColumnType.NUMBER, "Saldo");
		data.addRows(1);
		data.setValue(0, 0, "");
		data.setValue(0, 1, value);
		return data;
	}
	
	@Override
	public void loadDateForCharts(Date startDate, Date endDate) {
		clientFactory.getAppLoadingView().startProcessing();
		Request<List<OutcomeDataProxy>> req = clientFactory.getRequestFactory().getOutcomeDataRequest().findOutcomeDataByUserBetweenDates(startDate, endDate);
		req.fire(new Receiver<List<OutcomeDataProxy>>() {
			public void onSuccess(List<OutcomeDataProxy> returnedOutcomeData) {
				loadCharts(returnedOutcomeData);
			}
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
				clientFactory.getAppLoadingView().stopProcessing();
			}
		});

	}

}
